import { createPool, Pool, FieldInfo, MysqlError } from "mysql";
import { IMysqlConfig } from "../../etc/LyuInterface";

type TWhere = {
    [x: string]: string | number | {
        value: string | number | string[] | number[],
        type?: "&" | "|",
        comp?: ">" | "<" | "=" | "IN"
    }
};


function doWhere(where: TWhere) {
    let whereStr = ``;
    for (const key in where) {
        if (Object.prototype.hasOwnProperty.call(where, key)) {
            const value = where[key];
            if (typeof value == "object") {
                let keyValue = value.value;
                let type = value.type;

                let comp = value.comp == undefined ? "=" : value.comp;
                keyValue = typeof keyValue == "string" ? `'${keyValue}'` : keyValue;

                if (Array.isArray(value.value)) {
                    comp = "IN";
                    keyValue = `(${(value.value).toString()})`;
                }

                if (whereStr.length > 0) {
                    if (type == undefined || type == "&") {
                        whereStr += " AND ";
                    } else if (type == "|") {
                        whereStr += " OR ";
                    }
                }
                whereStr += `${key} ${comp} ${keyValue}`;
                continue;
            } else {
                if (whereStr.length > 0) {
                    whereStr += " AND ";
                }
                let keyValue = typeof value == "string" ? `'${value}'` : value;
                whereStr += `${key} = ${keyValue}`;
            }
        }
    }
    return whereStr;
}

export default class LMysql {
    private sqlPool!: Pool;
    private tbl!: string;

    constructor(conf: IMysqlConfig) {
        this.sqlPool = createPool(conf);
    }

    async query(sql: string) {
        return new Promise<any>((resolve, reject) => {
            this.sqlPool.getConnection((error, conn) => {
                if (error) {
                    resolve({ error: { coerrnode: -1, sqlMessage: "连接池创建错误" } });
                }
                conn.query(sql, (err: MysqlError | null, results?: any, fields?: FieldInfo[]) => {
                    conn.release();
                    resolve({ error: err, results: results, fields: fields });
                });
            })
        });
    }

    getSelectSql(fields: string[] | "*", table: string, where: TWhere) {
        let fieldsStr = "";
        if (fields == "*") {
            fieldsStr = "*";
        } else {
            for (let i = 0; i < fields.length; i++) {
                fieldsStr += fields[i] + ",";
            }
            fieldsStr = fieldsStr.substring(0, fieldsStr.length - 1);
        }

        let whereStr = doWhere(where);

        let sql = `SELECT ${fieldsStr} FROM ${table} WHERE ${whereStr};`;
        return sql;
    }

    async select(fields: string[] | "*", table: string, where: TWhere) {
        let sql = this.getSelectSql(fields, table, where);
        return await this.query(sql);
    }

    getInsertSql(fields: { [x: string]: string | number }, table: string) {
        let keys = "";
        let values = "";
        for (const key in fields) {
            if (Object.prototype.hasOwnProperty.call(fields, key)) {
                const value = fields[key];
                let keyValue = typeof value == "string" ? `'${value}'` : value;
                keys += key + ",";
                values += keyValue + ",";
            }
        }
        keys = keys.substring(0, keys.length - 1);
        values = values.substring(0, values.length - 1);
        let sql = `INSERT INTO ${table} (${keys}) VALUES (${values});`;
        return sql;
    }

    async insert(fields: { [x: string]: string | number }, table: string) {
        let sql = this.getInsertSql(fields, table);
        return await this.query(sql);
    }

    getUpdateSql(fields: { [x: string]: string | number }, table: string, where: TWhere) {
        let fielsStr = "";
        for (const key in fields) {
            if (Object.prototype.hasOwnProperty.call(fields, key)) {
                const value = fields[key];
                let keyValue = typeof value == "string" ? `'${value}'` : value;
                fielsStr += `${key} = ${keyValue},`;
            }
        }
        fielsStr = fielsStr.substring(0, fielsStr.length - 1);
        let whereStr = doWhere(where);

        let sql = `UPDATE ${table} SET ${fielsStr} WHERE ${whereStr};`;
        return sql;
    }

    async update(fields: { [x: string]: string | number }, table: string, where: TWhere) {
        let sql = this.getUpdateSql(fields, table, where);
        return await this.query(sql);
    }

    async count(table: string, where: TWhere) {
        let whereStr = doWhere(where);
        let sql = `SELECT COUNT(*) as count FROM ${table} WHERE ${whereStr}`;
        return await this.query(sql);
    }
}